#pragma once

#include "GameDeviceSingleton.h"
#include <vector>
#include <map>
#include "QuadTree.h"
#include "EntityInteractive.h"

/*
@author TriLVH
@description management object with filter with quadtree by viewport
*/

class EntityManager {
private:
	// contains entity get from quadtree, entity background matrix
	QuadTree* _quadtree;
	ContraEntity* _contra;
	std::vector<CollistionOutput*> _listColis;
	std::vector<CollistionOutput*>::iterator itColis;
	std::map<int, AbstractEntity*>* _currentEntities;
	std::map<int, AbstractEntity*>::iterator it;

	void _update(long timetick) {
		_quadtree->GetListObjectInRect(GameDeviceSingleton::getInstance()->getViewPort()->getQuadTreeView());
		_currentEntities = _quadtree->curGameObjects;

		for(it = _currentEntities->begin(); it != _currentEntities->end(); it++) {
			it->second->update(timetick);
		}
	}

	void _updateContraInteract() {
		//if (_contra->getData()->isDead) return;
		_quadtree->getCollistionObjects(_contra, _listColis);
		for (int i = 0; i < _listColis.size(); i++) {
			EntityInteractive::interact(_contra, _listColis.at(i));
		}			
	}

	void _updateBulletInteract() {
		BULLET_CONTAINER* container;
		container = GameDeviceSingleton::getInstance()->getGameBullet()->getArmyBullets();	
		_updateBulletContainerInteractWithContra(container);
		_updateBulletContainerInteractWithArmy(container, false);
		container = GameDeviceSingleton::getInstance()->getGameBullet()->getPlayerBullets();
		_updateBulletContainerInteractWithArmy(container, true);
	}

	void _updateBulletContainerInteractWithContra(BULLET_CONTAINER *container) {
		BULLET_CONTAINER::iterator it;

		_quadtree->getCollistionObjects(GameDeviceSingleton::getInstance()->getPlayerRect(), _listColis, container);
		for (itColis = _listColis.begin(); itColis != _listColis.end(); itColis++) {
			EntityInteractive::interactWithBulletArmy(_contra, *(itColis));
		}
	}

	void _updateBulletContainerInteractWithArmy(BULLET_CONTAINER* container, bool isBulletContra) {
		BULLET_CONTAINER::iterator it;

		for (it = container->begin(); it != container->end(); it++) {
			_quadtree->getCollistionObjects(it->second, _listColis);
			for (itColis = _listColis.begin(); itColis != _listColis.end(); itColis++) {
				EntityInteractive::interactWithBulletPlayer(it->second, *(itColis), isBulletContra);
			}
		}
	}

	void _updateRunningSoilderInteract(AbstractEntity* abstractEntity) {
		int sizeCollis;
		// Get list collis with army running soilder
		_quadtree->getCollistionObjects(abstractEntity->getAbstractData()->getRect(), _listColis);
		// Loop on list collis to check interact
		sizeCollis = _listColis.size();
		for (int i = 0; i < sizeCollis; i++) {
			EntityInteractive::interact(abstractEntity, _listColis.at(i));
		}
	}

	void _updateArmyInteract() {
		AbstractEntity* abstractEntity;
		for (it = _currentEntities->begin(); it != _currentEntities->end(); it++) {
			// Get entity on view of quadtree
			abstractEntity = it->second;
			// Check type of army
			if (abstractEntity->getAbstractData()->getType() == _ID_ARMY_RUNNING_SOLDIER
				|| abstractEntity->getAbstractData()->getType() == _ID_MAP_STAGE3_TANK_1) {
				_updateRunningSoilderInteract(abstractEntity);
			}
			// check type of item
			if (abstractEntity->getAbstractData()->getType() == _ID_ITEM_1) {
				_updateRunningSoilderInteract(abstractEntity);
			}

			//check type of stone
			if(abstractEntity->getAbstractData()->getType() == _ID_MAP_STAGE2_STONE_1)
			{
				_updateStoneInteract(abstractEntity);
			}

			//check type of Boom
			if(abstractEntity->getAbstractData()->getType() == _ID_MAP_STAGE3_BOOM_1)
			{
				_updateBoomInteract(abstractEntity);
			}

			//check type of boss 3 items
			if(abstractEntity->getAbstractData()->getType() == _ID_MAP_STAGE3_BOSS_1)
			{
				_updateBossItemInteract(abstractEntity);
			}

		}
	}

	/*Stone interact ground*/
	void _updateStoneInteract(AbstractEntity* abstractEntity)
	{
		int sizeCollis;
		//Get list collis with stone
		_quadtree->getCollistionObjects(abstractEntity, _listColis);
		sizeCollis = _listColis.size();
		for (int i = 0; i < sizeCollis; i++) {
			EntityInteractive::interactStoneAndGround(abstractEntity, _listColis.at(i)->object, _listColis.at(i));
		}
	}

	/*Boss item interact ground*/
	void _updateBossItemInteract(AbstractEntity* abstractEntity)
	{
		int sizeCollis;
		//Get list collis with boss item
		if(abstractEntity->getAbstractData()->subRect != NULL && abstractEntity->getAbstractData()->subRect->size() > 0)
		{
			vector<Rect*>::iterator it = abstractEntity->getAbstractData()->subRect->begin();
			for(; it != abstractEntity->getAbstractData()->subRect->end(); it++)
			{
				_quadtree->getCollistionObjects(*it, _listColis);
				sizeCollis = _listColis.size();
				for (int i = 0; i < sizeCollis; i++) {
					EntityInteractive::interactBoss3Items(abstractEntity, _listColis.at(i)->object, _listColis.at(i), it - abstractEntity->getAbstractData()->subRect->begin());
				}
			}
		}
	}

	//void _updateBossIInteract(AbstractEntity* abstractEntity)
	//{
	//	int sizeCollis;
	//	//Get list collis with boss item
	//	if(abstractEntity->getAbstractData()->subRect != NULL && abstractEntity->getAbstractData()->subRect->size() > 0)
	//	{
	//		vector<Rect*>::iterator it = abstractEntity->getAbstractData()->subRect->begin();
	//		for(; it != abstractEntity->getAbstractData()->subRect->end(); it++)
	//		{
	//			_quadtree->getCollistionObjects(*it, _listColis);
	//			sizeCollis = _listColis.size();
	//			for (int i = 0; i < sizeCollis; i++) {
	//				EntityInteractive::interactWithBoss1Item(abstractEntity, _listColis.at(i)->object, _listColis.at(i), it - abstractEntity->getAbstractData()->subRect->begin());
	//			}
	//		}
	//	}
	//}

	void _updateBoomInteract(AbstractEntity* abstractEntity)
	{
		int sizeCollis;
		//Get list collis with stone
		_quadtree->getCollistionObjects(abstractEntity, _listColis);
		sizeCollis = _listColis.size();
		for (int i = 0; i < sizeCollis; i++) {
			EntityInteractive::interactWithBoom(abstractEntity, _listColis.at(i)->object, _listColis.at(i));
		}
	}

	void _updateInteractive() {
		_updateContraInteract();	
		_updateArmyInteract();
		_updateBulletInteract();
	}
public:
	EntityManager() {
		_quadtree = new QuadTree(GameLevel1);
		_currentEntities = NULL;
	}

	void setContra(ContraEntity* contra) {
		_contra = contra;
	}

	// Constructor to map these collection to collection in GameRun 
	// Draw all entity
	void draw(long timetick) {
		if (_currentEntities == NULL) return;
		for(it = _currentEntities->begin(); it != _currentEntities->end(); it++) {
			it->second->draw(timetick);
		}
	}

	// Update all entity
	void update(long timetick) {
		_update(timetick);
		_updateInteractive();
	}

	// Load new Game
	void changeMap(int level) {
		_quadtree->changeMap(level);
	}

	// init all entity
	void init() {

	}
};